package demo;

import java.util.EnumSet;

import util.Function;
import util.StringReader;
import util.Util;
import util.ZachError;
import zach.env.Env;
import zach.env.LexType;
import zach.env.MarkPattern;
import zach.env.WordType;
import zach.parser.Lex;
import zach.parser.Word;

public class ShowLexParse {

	// 演示可装配词法分析器,和用可装配词法分析器进行分析
	public static void main( String[] args ) {
		// 这个try没什么意思
		try {
			// 首先我们要创建一个词法分析器,这个词法分析器是可装配的
			// 创建词法分析器使用函数Lex.WordReader( EnumSet<LexType> lexTypes, MarkPattern[] markPatterns );
			// lexTypes是一个LexType枚举集合,LexType包含两个枚举值,Token和Value,Token表示能解析id和关键字,Value表示能解析字符,字符串和数字
			// EnumSet是Java的内置类,在Java5时提供
			// markPatterns表示能解析的符号,我们稍后再说
			// 所有解析器都能解析空白符和注释

			// 第一次尝试
			System.out.println( "---------------First Try-----------------" );

			// 下面我们创建一个词法分析器,该词法分析器能解析Token,即id和关键字,注意函数EnumSet的使用
			Function<Word, StringReader> readToken = Lex.WordReader( EnumSet.of( LexType.Token ), new MarkPattern[] {} );

			// readToken是个函数对象,它有一个方法call,Word readToken( StringReader )
			// StringReader是一个字符串阅读器接口,注意是接口不是类,这个接口只要求eat方法和cur方法
			// 我们使用最基本的BasicStringReader进行测试
			StringReader stringReader = new Util.BasicStringReader( "if abc def while" );

			// 开始分析,每调用一次readToken函数,它会从StringReader中读出一个词
			// 词以类型Word表示,包括字段wordType和value
			// wordType的类型是枚举WordType,表示该词的类型
			// 其中数字类型,字符串类型,字符类型和ID类型有值,值是一个Integer数组,本来考虑用String,但是char的限制有点多(处理不了EOF),故改为用int
			Word word = readToken.call( stringReader ); // 从stringReader中一个词
			// 读到EOF为止
			while ( word.type != WordType.EOF ) {
				System.out.print( word.type.name() ); // 打印该词的类型,注意Java的Enum是可以转换成字符串的

				// 如果有值,打印值
				if ( word.value != null ) {
					System.out.print( "\t" + Util.intArrayToString( word.value ) );
				}

				word = readToken.call( stringReader ); // 读下一个词
				System.out.println();
			}
		}
		catch ( Exception e ) {
			e.printStackTrace();
		}
		System.out.println();

		try {
			// 第二次尝试
			System.out.println( "---------------Second Try-----------------" );

			// 下面我们创建一个词法分析器,该词法分析器能解析Value,即字符,字符串和数字
			Function<Word, StringReader> readValue = Lex.WordReader( EnumSet.of( LexType.Value ), new MarkPattern[] {} );

			StringReader stringReader = new Util.BasicStringReader( "123 123.45 123.45e456 123e234 0x1234ABCD 'a' \"abc\tabc\"" );

			Word word = readValue.call( stringReader ); // 从stringReader中一个词
			// 读到EOF为止
			while ( word.type != WordType.EOF ) {
				System.out.println( word.type.name() + ( word.value == null ? "" : "\t" + Util.intArrayToString( word.value ) ) ); // 打印类型和值
				word = readValue.call( stringReader ); // 读下一个词
			}
		}
		catch ( Exception e ) {
			e.printStackTrace();
		}
		System.out.println();

		try {
			// 第三次尝试
			System.out.println( "---------------Third Try-----------------" );

			// 下面我们创建一个词法分析器,该词法分析器能解析>>>,>>和>
			// 这里注意WordReader的第二个参数,它是一个数组,每个项是一个类型为MarkPattern的值
			// 所有Zach的MarkPattern已经预先准备在Env.ZachMarks里了
			// 另外注意空EnumSet的构造方式
			Function<Word, StringReader> readMark = Lex.WordReader( EnumSet.noneOf( LexType.class ), new MarkPattern[] { Env.ZachMarks.Great,
					Env.ZachMarks.ShiftRight, Env.ZachMarks.ShiftRightLogic } );

			StringReader stringReader = new Util.BasicStringReader( ">>>>> >> >" );

			Word word = readMark.call( stringReader ); // 从stringReader中一个词
			// 读到EOF为止
			while ( word.type != WordType.EOF ) {
				System.out.println( word.type.name() + ( word.value == null ? "" : "\t" + Util.intArrayToString( word.value ) ) ); // 打印类型和值
				word = readMark.call( stringReader ); // 读下一个词
			}
		}
		catch ( Exception e ) {
			e.printStackTrace();
		}
		System.out.println();

		try {
			// 第四次尝试
			System.out.println( "---------------Forth Try-----------------" );

			// 下面我们创建一个词法分析器,该词法分析器只能解析和>
			// 注意它和第三次尝试的结果的不同
			Function<Word, StringReader> readMark = Lex.WordReader( EnumSet.noneOf( LexType.class ), new MarkPattern[] { Env.ZachMarks.Great } );

			StringReader stringReader = new Util.BasicStringReader( ">>>>> >> >" );

			Word word = readMark.call( stringReader ); // 从stringReader中一个词
			// 读到EOF为止
			while ( word.type != WordType.EOF ) {
				System.out.println( word.type.name() + ( word.value == null ? "" : "\t" + Util.intArrayToString( word.value ) ) ); // 打印类型和值
				word = readMark.call( stringReader ); // 读下一个词
			}
		}
		catch ( Exception e ) {
			e.printStackTrace();
		}
		System.out.println();

		try {
			// 第五次尝试
			System.out.println( "---------------Fifth Try-----------------" );

			// 创建一个全解析器,实际上语法分析中不会用到用到全解析器,这里只是示范一下用法
			// Env.allZachMarks存放了全部的Zach符号
			Function<Word, StringReader> readWord = Lex.WordReader( EnumSet.of( LexType.Token, LexType.Value ), Env.allZachMarks );

			StringReader stringReader = new Util.BasicStringReader( "abc if /*abcd*/ \n //abcd\n >>>> 123.45" );

			Word word = readWord.call( stringReader ); // 从stringReader中一个词
			// 读到EOF为止
			while ( word.type != WordType.EOF ) {
				System.out.println( word.type.name() + ( word.value == null ? "" : "\t" + Util.intArrayToString( word.value ) ) ); // 打印类型和值
				word = readWord.call( stringReader ); // 读下一个词
			}
		}
		catch ( Exception e ) {
			e.printStackTrace();
		}
		System.out.println();

		try {
			// 第六次尝试
			System.out.println( "---------------Sixth Try-----------------" );

			// 演示异常,readWord函数会抛出异常,以最简单的UnexptedEOF为例
			Function<Word, StringReader> readWord = Lex.WordReader( EnumSet.of( LexType.Token, LexType.Value ), Env.allZachMarks );

			StringReader stringReader = new Util.BasicStringReader( "/*abc" ); // 未终结的EOF

			Word word = readWord.call( stringReader ); // 从stringReader中一个词
			// 读到EOF为止
			while ( word.type != WordType.EOF ) {
				System.out.println( word.type.name() + ( word.value == null ? "" : "\t" + Util.intArrayToString( word.value ) ) ); // 打印类型和值
				word = readWord.call( stringReader ); // 读下一个词
			}
		}
		catch ( ZachError e ) {
			// 错误处理很简单,ZachError中的errorNumber字段存放了错误号,仅此而已
			System.out.print( "Error: " + e.errorNumber.toString() );
		}
	}
}
